package com.ruibang.glass.sale.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruibang.glass.common.constants.CommonErrorCode;
import com.ruibang.glass.common.constants.RedisKey;
import com.ruibang.glass.common.domain.DictInfo;
import com.ruibang.glass.common.domain.ProductInfo;
import com.ruibang.glass.common.domain.camunda.BpmProcessInstanceStatus;
import com.ruibang.glass.common.domain.material.MaterialCpBcpItemsInfo;
import com.ruibang.glass.common.domain.material.MaterialProductsInInfo;
import com.ruibang.glass.common.domain.material.MaterialProductsOut;
import com.ruibang.glass.common.utils.ApproveUserNameUtils;
import com.ruibang.glass.frequencycontrol.annotation.RedissonLock;
import com.ruibang.glass.sale.constant.Constants;
import com.ruibang.glass.sale.constant.SaleErrorCode;
import com.ruibang.glass.sale.constant.SaleMenuIdCode;
import com.ruibang.glass.sale.domain.req.GSaleReturnIventoryReq;
import com.ruibang.glass.sale.entity.*;
import com.ruibang.glass.sale.feign.CamundaApi;
import com.ruibang.glass.sale.feign.MaterialApi;
import com.ruibang.glass.sale.feign.PortalApi;
import com.ruibang.glass.sale.mapper.GSaleOrderMapper;
import com.ruibang.glass.sale.mapper.GSaleReturnExchangeOrderMapper;
import com.ruibang.glass.sale.mapper.GSaleReturnInventoryMapper;
import com.ruibang.glass.sale.mapper.SaleReturnInventoryProductMapper;
import com.ruibang.glass.sale.service.*;
import com.teaming.cloud.framework2.autoconfigure.redis.RedisSingleService;
import com.teaming.cloud.framework2.common.constant.CommonConstant;
import com.teaming.cloud.framework2.common.exception.ServiceException;
import com.teaming.cloud.framework2.common.model.ResultBody;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.ruibang.glass.common.constants.RedisKey.MATERIAL_IN_WAREHOUSE_NUMBER;
import static com.ruibang.glass.common.constants.RedisKey.MATERIAL_OR_WAREHOUSE_NUMBER;


@Slf4j
@Service
public class GSaleReturnInventoryServiceImpl extends ServiceImpl<GSaleReturnInventoryMapper, GSaleReturnInventory> implements GSaleReturnInventoryService {
    @Autowired
    private SaleReturnInventoryProductMapper saleReturnInventoryProductMapper;

    @Autowired
    private RedisSingleService rediservice;

    @Autowired
    private PortalApi portalApi;
    @Autowired
    private MaterialApi materialApi;

    @Autowired
    private GSaleOrderMapper saleOrderMapper;

    @Autowired
    private SaleShippingApplicationService saleShippingApplicationService;

    @Autowired
    private GSaleReturnExchangeOrderMapper saleReturnExchangeOrderMapper;

    private static final String PURCHASE_IN_NUMBER = "purchase_in_number";

    @Autowired
    private CamundaApi camundaApi;

    @Override
    public IPage<GSaleReturnInventory> getPage(GSaleReturnIventoryReq gSaleReturnIventoryReq) {

        LambdaQueryWrapper<GSaleReturnInventory> queryWrapper = Wrappers.<GSaleReturnInventory>lambdaQuery();
        if (StringUtils.isNotBlank(gSaleReturnIventoryReq.getInventoryNumber())) {
            queryWrapper.like(GSaleReturnInventory::getInventoryNumber, gSaleReturnIventoryReq.getInventoryNumber());
        }
        if (StringUtils.isNotBlank(gSaleReturnIventoryReq.getWarehouse())) {
            queryWrapper.eq(GSaleReturnInventory::getWarehouse, gSaleReturnIventoryReq.getWarehouse());
        }
        if (StringUtils.isNotBlank(gSaleReturnIventoryReq.getHandler())) {
            queryWrapper.eq(GSaleReturnInventory::getHandlerId, gSaleReturnIventoryReq.getHandler());
        }
        if (StringUtils.isNotBlank(gSaleReturnIventoryReq.getReturnType())) {
            queryWrapper.eq(GSaleReturnInventory::getReturnType, gSaleReturnIventoryReq.getReturnType());
        }
        if (StringUtils.isNotBlank(gSaleReturnIventoryReq.getInventoryType())) {
            queryWrapper.eq(GSaleReturnInventory::getReturnType, gSaleReturnIventoryReq.getInventoryType());
        }
        if (gSaleReturnIventoryReq.getInventoryStartDate() != null) {
            queryWrapper.ge(GSaleReturnInventory::getInventoryDate, gSaleReturnIventoryReq.getInventoryStartDate());
        }
        if (gSaleReturnIventoryReq.getInventoryEndDate() != null) {
            queryWrapper.le(GSaleReturnInventory::getInventoryDate, gSaleReturnIventoryReq.getInventoryEndDate());
        }
        Page<GSaleReturnInventory> saleShippingApplicationPage = baseMapper.selectPage(new Page<>(gSaleReturnIventoryReq.getPageNo(), gSaleReturnIventoryReq.getPageSize()),
                queryWrapper.orderByDesc(GSaleReturnInventory::getUpdateTime)
        );
        if (CollectionUtils.isNotEmpty(saleShippingApplicationPage.getRecords())) {
            Map<Object, Object> userMap = rediservice.hmget(RedisKey.USER_GROUP_TYPE);
            List<String> businessKeys = saleShippingApplicationPage.getRecords().stream().map(GSaleReturnInventory::getCpBcpId).collect(Collectors.toList());
            Map<String, BpmProcessInstanceStatus> processMap = null;
            //获取业务流程状态
            ResultBody<List<BpmProcessInstanceStatus>> resultBody = camundaApi.queryProcessInstanceStatus(businessKeys);
            if (resultBody != null && CollectionUtils.isNotEmpty(resultBody.getData())) {
                processMap = resultBody.getData().stream().collect(Collectors.toMap(bp -> bp.getBusinessKey(), bp -> bp, (bp1, bp2) -> bp1));
            }
            if (processMap != null) {
                for (GSaleReturnInventory saleReturnInventory : saleShippingApplicationPage.getRecords()) {
                    if (StringUtils.isNotEmpty(saleReturnInventory.getCpBcpId())) {
                        if (processMap.get(saleReturnInventory.getCpBcpId()) != null) {
                            saleReturnInventory.setNodeName(processMap.get(saleReturnInventory.getCpBcpId()).getNodeName());
                            String userId = processMap.get(saleReturnInventory.getCpBcpId()).getUserId();
                            if (StringUtils.isNotBlank(userId) && !StringUtils.equals(userId, "null")) {
                                String approveName = ApproveUserNameUtils.getApproveName(userId, userMap);
                                saleReturnInventory.setApproveUser(approveName);
                            }
                        }
                    }
                }
            }
        }


        return saleShippingApplicationPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveGSaleReturnInventory(GSaleReturnInventory saleReturnInventory) {
        baseMapper.insert(saleReturnInventory);
        if (CollectionUtils.isNotEmpty(saleReturnInventory.getSaleReturnInventoryProductList())) {
            for (SaleReturnInventoryProduct saleReturnInventoryProduct : saleReturnInventory.getSaleReturnInventoryProductList()) {
                saleReturnInventoryProduct.setInventoryId(saleReturnInventory.getId());
                saleReturnInventoryProductMapper.insert(saleReturnInventoryProduct);
            }
        }

    }

    @Override
    public void updateGSaleReturnInventory(GSaleReturnInventory saleReturnInventory) {
        if (CollectionUtils.isEmpty(saleReturnInventory.getSaleReturnInventoryProductList())) {
            throw new ServiceException(SaleErrorCode.BCP_CP_OUT_BOUND_NO_PRODUCT.getCode(), SaleErrorCode.BCP_CP_OUT_BOUND_NO_PRODUCT.getMsg());
        }
        for (SaleReturnInventoryProduct saleReturnInventoryProduct : saleReturnInventory.getSaleReturnInventoryProductList()) {
            saleReturnInventoryProductMapper.updateById(saleReturnInventoryProduct);
        }
        saleReturnInventory.setIsStatus(Constants.TWO_STR);
        baseMapper.updateById(saleReturnInventory);

        Map<Object, Object> userMap = rediservice.hmget(RedisKey.USER_GROUP_TYPE);
        MaterialProductsInInfo materialProductsInInfo = new MaterialProductsInInfo();
        materialProductsInInfo.setInStorageOrderNo(saleReturnInventory.getInventoryNumber());
        materialProductsInInfo.setNumber(saleReturnInventory.getInventoryNumber());
        materialProductsInInfo.setPreparer((String) userMap.get(saleReturnInventory.getCreateUserId()));
        materialProductsInInfo.setPreparerId(saleReturnInventory.getCreateUserId());
        materialProductsInInfo.setCustomerName(saleReturnInventory.getCustomer());
        materialProductsInInfo.setWarehouseName(saleReturnInventory.getWarehouse());
        materialProductsInInfo.setHandler((String) userMap.get(saleReturnInventory.getCreateUserId()));
        materialProductsInInfo.setNodeName(saleReturnInventory.getReturnNumber());
        materialProductsInInfo.setReturnId(saleReturnInventory.getId());
        materialProductsInInfo.setType(Constants.ELEVEN_STR);
        materialProductsInInfo.setInCreationTime(LocalDate.now());
        List<MaterialCpBcpItemsInfo> materialCpBcpItemsInfoList = new ArrayList<>();
        for (SaleReturnInventoryProduct saleReturnInventoryProduct : saleReturnInventory.getSaleReturnInventoryProductList()) {
            //更具订单号计算退货数量
//            GSaleOrderManagement gSaleOrderManagement = saleOrderMapper.selectById(saleReturnInventoryProduct.getOrderId());
//            BigDecimal returnTotal = gSaleOrderManagement.getReturnQuantity().add(saleReturnInventoryProduct.getReturnQuantity());
//            gSaleOrderManagement.setReturnQuantity(returnTotal);
//            saleOrderMapper.updateById(gSaleOrderManagement);
            SaleReturnInventoryProduct saleReturnInventoryProduct1 = baseMapper.getSaleReturnInventoryProduct(saleReturnInventoryProduct.getTrayId());

//            ResultBody<ProductInfo> productById = portalApi.getProductById(saleReturnInventoryProduct.getProductId());
            MaterialCpBcpItemsInfo materialCpBcpItemsInfo = MaterialCpBcpItemsInfo.builder()
                    .itemId(saleReturnInventoryProduct.getProductId())
                    .itemCode(saleReturnInventoryProduct.getProductCode())
                    .aTypeShelf(saleReturnInventoryProduct.getTrayId())
                    .itemName(saleReturnInventoryProduct.getProduct())
                    .specification(saleReturnInventoryProduct.getProductSpecification())
                    .quantity(saleReturnInventoryProduct.getReturnQuantity())
                    .batchNumber(saleReturnInventoryProduct.getBatchNumber())
                    .returnId(saleReturnInventoryProduct.getId())
                    .orderId(saleReturnInventoryProduct.getOrderId())
                    .build();
            if (saleReturnInventoryProduct1 != null) {
                String locationName = baseMapper.getLocationName(saleReturnInventoryProduct1.getStorageLocation());
                materialCpBcpItemsInfo.setUnit(saleReturnInventoryProduct1.getUnit());
                materialCpBcpItemsInfo.setWarehouseName(saleReturnInventoryProduct1.getWareHouseName());
                materialCpBcpItemsInfo.setWarehouseId(saleReturnInventoryProduct1.getWareHouseId());
                materialCpBcpItemsInfo.setGrade(saleReturnInventoryProduct1.getModelGrade());
                materialCpBcpItemsInfo.setModelGrade(saleReturnInventoryProduct1.getModelGrade());
                materialCpBcpItemsInfo.setBatchNumber(saleReturnInventoryProduct1.getBatchNumber());
                materialCpBcpItemsInfo.setStorageLocationName(locationName);
                materialCpBcpItemsInfo.setStorageLocationId(saleReturnInventoryProduct1.getStorageLocation());
                materialCpBcpItemsInfo.setSpecification(saleReturnInventoryProduct1.getProductSpecification());
            }
            materialCpBcpItemsInfoList.add(materialCpBcpItemsInfo);
        }
        materialProductsInInfo.setMaterialCpBcpItemsList(materialCpBcpItemsInfoList);
        if (saleReturnInventory.getWarehouse().equals(Constants.TWO_STR)) {
            List<MaterialProductsInInfo> materialProductsInInfos = new ArrayList<>();
            materialProductsInInfo.setMenuId(SaleMenuIdCode.MENU_ID_BCPK_IN.getMsg());
            materialProductsInInfo.setWarehouseName(Constants.BCP_WARE_HOUSE);
            materialProductsInInfos.add(materialProductsInInfo);
            materialApi.addMaterialBCPProductsInInfo(materialProductsInInfos);
        } else {
            materialProductsInInfo.setWarehouseName(Constants.CP_WARE_HOUSE);
            materialProductsInInfo.setMenuId(SaleMenuIdCode.MENU_ID_CPK_IN.getMsg());
            materialApi.addMaterialCpProductsInInfo(materialProductsInInfo);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateGSaleReturnInventoryReQuality(List<SaleReturnInventoryProduct> saleReturnInventoryProductList) {
        Map<String, List<SaleReturnInventoryProduct>> collect = saleReturnInventoryProductList.stream().collect(Collectors.groupingBy(SaleReturnInventoryProduct::getOrderId));
        for (String orderId : collect.keySet()) {
            BigDecimal reQ = BigDecimal.ZERO;
            GSaleOrderManagement saleOrderManagement = saleOrderMapper.selectById(orderId);
            if (saleOrderManagement.getReturnQuantity() != null) {
                reQ = reQ.add(saleOrderManagement.getReturnQuantity());
            }
            if (collect.get(orderId) != null) {
                for (SaleReturnInventoryProduct saleReturnInventoryProduct : collect.get(orderId)) {
                    reQ = reQ.add(saleReturnInventoryProduct.getReturnQuantity());
                }
            }
            saleOrderManagement.setReturnQuantity(reQ);
            saleOrderMapper.updateById(saleOrderManagement);
        }

        for (SaleReturnInventoryProduct saleReturnInventoryProduct : saleReturnInventoryProductList) {
            SaleReturnInventoryProduct saleReturnInventoryProduct1 = saleReturnInventoryProductMapper.selectById(saleReturnInventoryProduct.getId());
            SaleShippingApplication one = saleShippingApplicationService.getOne(Wrappers.<SaleShippingApplication>lambdaQuery().eq(SaleShippingApplication::getDeliveryOrderNumber, saleReturnInventoryProduct1.getDeliveryOrderNumber()).last("limit 1"));
            if (one.getReturnedQuantity() == null) {
                one.setReturnedQuantity(saleReturnInventoryProduct1.getReturnQuantity());
            } else {
                BigDecimal add = saleReturnInventoryProduct1.getReturnQuantity().add(one.getReturnedQuantity());
                one.setReturnedQuantity(add);
                saleShippingApplicationService.updateById(one);
            }

        }
        SaleReturnInventoryProduct saleReturnInventoryProduct1 = saleReturnInventoryProductMapper.selectById(saleReturnInventoryProductList.get(0).getId());
        GSaleReturnInventory gSaleReturnInventory = baseMapper.selectById(saleReturnInventoryProduct1.getInventoryId());
        GSaleReturnExchangeOrder gSaleReturnExchangeOrder = saleReturnExchangeOrderMapper.selectOne(Wrappers.<GSaleReturnExchangeOrder>lambdaQuery().eq(GSaleReturnExchangeOrder::getReturnNumber, gSaleReturnInventory.getReturnNumber()).last("limit 1"));
        if (gSaleReturnExchangeOrder != null) {
            gSaleReturnExchangeOrder.setReturnQuantity(Constants.ZERO_INT);
            Integer totalCount = Constants.ZERO_INT;
            for (SaleReturnInventoryProduct saleReturnInventoryProduct : saleReturnInventoryProductList) {
                totalCount = totalCount + saleReturnInventoryProduct.getReturnQuantity().intValue();
            }
            gSaleReturnExchangeOrder.setReturnQuantity(totalCount);
            saleReturnExchangeOrderMapper.updateById(gSaleReturnExchangeOrder);
        }
    }

    @Override
    public GSaleReturnInventory getGSaleReturnInventory(String id) {
        GSaleReturnInventory gSaleReturnInventory = baseMapper.selectById(id);
        List<SaleReturnInventoryProduct> saleReturnInventoryProductList = saleReturnInventoryProductMapper.selectList(Wrappers.<SaleReturnInventoryProduct>lambdaQuery().eq(SaleReturnInventoryProduct::getInventoryId, id));
        gSaleReturnInventory.setSaleReturnInventoryProductList(saleReturnInventoryProductList);
        return gSaleReturnInventory;
    }

    @Override
    public String generateNextSerialNumber() {
        String orMaterialInNumber = getORMaterialInNumber();
        return orMaterialInNumber;
    }


    @Override
    public String getINNumber() {
        String materialInNumber = getMaterialInNumber();
        return materialInNumber;
    }


    @RedissonLock(key = MATERIAL_IN_WAREHOUSE_NUMBER, prefixKey = "lock_")
    public String getMaterialInNumber() {
        String date = LocalDate.now().format(DateTimeFormatter.ofPattern(CommonConstant.DATE_FORMAT_UN_SEPARATE));
        date = "IN".concat(date);
        String code = "";

        Serializable number = rediservice.get(RedisKey.MATERIAL_IN_WAREHOUSE_NUMBER);
        if (number == null || StringUtils.isBlank(number.toString())) {
            ResultBody<String> resultBody = portalApi.getValueByCode(MATERIAL_IN_WAREHOUSE_NUMBER);
            if (resultBody != null && StringUtils.isNotBlank(resultBody.getData())) {
                number = resultBody.getData();
            }
        }
        if (number != null && StringUtils.isNotBlank(number.toString()) && number.toString().length() > 10) {
            String sequenceStr = number.toString().substring(10);
            int sequenceInt = Integer.parseInt(sequenceStr);
            sequenceInt = sequenceInt + 1;
            String newSequence = String.valueOf(sequenceInt);
            if (newSequence.length() == CommonConstant.FIVE_INT) {
                code = date.concat("0001");
            } else {
                code = date.concat(String.format("%04d", sequenceInt)); // 格式化数字为4位，不足部分用0填充
            }
        } else {
            code = date.concat("0001");
        }
        rediservice.set(RedisKey.MATERIAL_IN_WAREHOUSE_NUMBER, code);
        DictInfo info = new DictInfo();
        info.setCsdm(RedisKey.MATERIAL_IN_WAREHOUSE_NUMBER);
        info.setCsmc(code);
        portalApi.updateValueByCode(info);
        return code;
    }


    @RedissonLock(key = MATERIAL_IN_WAREHOUSE_NUMBER, prefixKey = "lock_")
    public String getORMaterialInNumber() {
        String date = LocalDate.now().format(DateTimeFormatter.ofPattern(CommonConstant.DATE_FORMAT_UN_SEPARATE));
        date = "OR".concat(date);
        String code = "";
        String newNumber = "";
        Serializable number = rediservice.get(MATERIAL_OR_WAREHOUSE_NUMBER);
        if (number == null || StringUtils.isBlank(number.toString())) {
            ResultBody<String> resultBody = portalApi.getValueByCode(MATERIAL_OR_WAREHOUSE_NUMBER);
            if (resultBody != null && StringUtils.isNotBlank(resultBody.getData())) {
                number = resultBody.getData();
                newNumber = SerialReturnNumberGenerator.generateNextSerialNumber(number.toString());
            } else {
                newNumber = date.concat("0001");
            }
        } else {
            newNumber = SerialReturnNumberGenerator.generateNextSerialNumber(number.toString());
        }
        rediservice.set(MATERIAL_OR_WAREHOUSE_NUMBER, newNumber);
        DictInfo info = new DictInfo();
        info.setCsdm(MATERIAL_OR_WAREHOUSE_NUMBER);
        info.setCsmc(newNumber);
        portalApi.updateValueByCode(info);
        return newNumber;
    }
}
